package main_package;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

public class MTSystem {

	static final int N = 4; // The N defines that we will use N-GRAMS
	HashMap<Sentence, Sentence> refTranslationMap;
	String systemName;
	public MTSystem(String systemName) 
	{
		this.systemName = systemName;
		refTranslationMap = new HashMap<Sentence, Sentence>();
	}
	
	public String GetName()
	{
		return systemName;
	}
	public void AddReferenceTranslationPair(Sentence ref, Sentence translation)
	{
		refTranslationMap.put(ref, translation);
	}
	
	// Count how many n grams of trans appear in ref
	public int CountNGrams(Sentence trans, Sentence ref, int N)
	{
		int count = 0;
		Entry<ArrayList<Sentence>,ArrayList<Integer>> nGrams = trans.ExtractNGrams(N);
		for(int i = 0; i < nGrams.getKey().size(); i++)
		{
			// Clip the number of occurances of each n-gram of trans in ref by the max number of its occurances in ref
			count +=  Math.min(nGrams.getValue().get(i), ref.FindNumOfSequenceOccurances(nGrams.getKey().get(i).GetWords()));
		}
		return count;
	}
	
	public static <T, E> T getKeyByValue(Map<T, E> map, E value) {
	    for (Entry<T, E> entry : map.entrySet()) {
	        if (value.equals(entry.getValue())) {
	            return entry.getKey();
	        }
	    }
	    return null;
	}
	public double CalcPn(int n)
	{
		double sumClippedScored = 0;
		double totalNumOfNgramsInAllCandidates = 0;
		for(Sentence trans : refTranslationMap.values())
		{
			// Count the clipped number of total occurances of n- grams of trans in ref
			sumClippedScored += CountNGrams(trans, getKeyByValue(refTranslationMap, trans), n);
			
			// Sum number of all n- grams in trans
			totalNumOfNgramsInAllCandidates += trans.Length() - (n - 1);
		}
		
		return sumClippedScored / totalNumOfNgramsInAllCandidates;
	}
	

	public double CalcBleuScore()
	{
		double bleu = 0;
		
		// Compute pn for all n-grams sizes
		for(int i = 1; i <= N; i++)
		{
			bleu += 1.0/N * Math.log(CalcPn(i));
		}
		return CalcBP() * Math.exp(bleu);
	}
		
	private double CalcBP()
	{
		int r = 0, c = 0;
		
		// Sum all reference lengths and all translations length
		for (Sentence ref : refTranslationMap.keySet()) 
		{
			r += ref.Length();
			c += refTranslationMap.get(ref).Length();
		}
		if (c > r)
			return 1.0;
		return Math.exp(1 - (double)r / c);
	}
}
